home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / OS / FWGraphx / Sources / FWPriRas.cpp < prev    next >
Encoding:
Text File  |  1995-11-08  |  38.6 KB  |  1,500 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWPriRas.cpp
  4. //    Release Version:    $ 1.0d11 $
  5. //
  6. //    Copyright:    © 1993, 1995 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWOS.hpp"
  11.  
  12. #if defined(FW_PROFILER_CALLS) && defined(__MWERKS__)
  13. #pragma profile on
  14. #endif
  15.  
  16. #ifndef FWPRIRAS_H
  17. #include "FWPriRas.h"
  18. #endif
  19.  
  20. #ifndef FWPICTUR_H
  21. #include "FWPictur.h"
  22. #endif
  23.  
  24. #ifndef FWBITMAP_H
  25. #include "FWBitmap.h"
  26. #endif
  27.  
  28. #ifndef FWTXTBUF_H
  29. #include "FWTxtBuf.h"
  30. #endif
  31.  
  32. #ifndef FWGRUTIL_H
  33. #include "FWGrUtil.h"
  34. #endif
  35.  
  36. #ifndef FWTXTSHP_H
  37. #include "FWTxtShp.h"
  38. #endif
  39.  
  40. #ifndef FWTXTBOX_H
  41. #include "FWTxtBox.h"
  42. #endif
  43.  
  44. #ifndef FWRECT_H
  45. #include "FWRect.h"
  46. #endif
  47.  
  48. #ifndef FWPOINT_H
  49. #include "FWPoint.h"
  50. #endif
  51.  
  52. #ifndef FWREGION_H
  53. #include "FWRegion.h"
  54. #endif
  55.  
  56. #ifndef FWPOLY_H
  57. #include "FWPoly.h"
  58. #endif
  59.  
  60. #ifndef FWICON_H
  61. #include "FWIcon.h"
  62. #endif
  63.  
  64. #ifndef FWGDEV_H
  65. #include "FWGDev.h"
  66. #endif
  67.  
  68. #ifndef FWODGEOM_H
  69. #include "FWODGeom.h"
  70. #endif
  71.  
  72. #ifndef FWMDASH_H
  73. #include "FWMDash.h"
  74. #endif
  75.  
  76. #ifndef FWMDASH_H
  77. #include "FWMDash.h"
  78. #endif
  79.  
  80. #ifndef   FWMEMMGR_H
  81. #include "FWMemMgr.h"
  82. #endif
  83.  
  84. // ----- OpenDoc Includes -----
  85.  
  86. #ifndef SOM_ODShape_xh
  87. #include <Shape.xh>
  88. #endif
  89.  
  90. // ----- Standard C Includes -----
  91.  
  92. #include <math.h>
  93.  
  94. // ----- Platform Includes -----
  95.  
  96. #if defined(FW_BUILD_MAC) && !defined(__LOWMEM__)
  97. #include <LowMem.h>
  98. #endif
  99.  
  100. #if defined(FW_BUILD_MAC) && !defined(__ICONS__)
  101. #include <Icons.h>
  102. #endif
  103.  
  104. //========================================================================================
  105. //    RunTime Info
  106. //========================================================================================
  107.  
  108. #if FW_LIB_EXPORT_PRAGMAS
  109. #pragma lib_export on
  110. #endif
  111.  
  112. #pragma segment FWGraphx_Rasterizer
  113.  
  114. //========================================================================================
  115. // Local macros to make rasterizer code more staightforward
  116. //========================================================================================
  117.  
  118. #ifdef FW_BUILD_WIN
  119.  
  120. #define FW_CHECK_RASTERIZER    \
  121.     FW_ASSERT(&gc == FW_gLastGC);
  122.     
  123. #endif
  124.  
  125. #ifdef FW_BUILD_MAC
  126.  
  127. #define FW_CHECK_RASTERIZER    \
  128.     FW_ASSERT(&gc == FW_gLastGC); \
  129.     FW_ASSERT(gc.GetGraphicDevice()->GetPlatformCanvas() == FW_QDGlobals.thePort);
  130.     
  131. #endif
  132.  
  133. #define FW_CHECK_RENDER_VERB \
  134.     if (renderVerb == FW_kNoRendering) \
  135.         return;
  136.     
  137. #define FW_RASTERIZER_PROLOG \
  138.     FW_CHECK_RASTERIZER \
  139.     FW_CGraphicDevice* device = gc.GetGraphicDevice();
  140.     
  141. #define FW_CHECK_INK \
  142.     FW_ASSERT((const void*)ink != NULL);
  143.     
  144. #define FW_CHECK_STYLE \
  145.     FW_ASSERT((const void*)style != NULL);
  146.     
  147. #define FW_CHECK_FONT \
  148.     FW_ASSERT((const void*)font != NULL);
  149.     
  150.  
  151. //========================================================================================
  152. //    class FW_CPrivRasterizer
  153. //========================================================================================
  154.  
  155. //----------------------------------------------------------------------------------------
  156. //    FW_CPrivRasterizer::FW_CPrivRasterizer
  157. //----------------------------------------------------------------------------------------
  158.  
  159. FW_CPrivRasterizer::FW_CPrivRasterizer()
  160. {
  161. }
  162.  
  163. //----------------------------------------------------------------------------------------
  164. //    FW_CPrivRasterizer::~FW_CPrivRasterizer
  165. //----------------------------------------------------------------------------------------
  166.  
  167. FW_CPrivRasterizer::~FW_CPrivRasterizer()
  168. {
  169. }
  170.  
  171. //----------------------------------------------------------------------------------------
  172. //    FW_CPrivRasterizer::RenderRect
  173. //----------------------------------------------------------------------------------------
  174.  
  175. void FW_CPrivRasterizer::RenderRect(FW_CGraphicContext& gc,
  176.                                 const FW_CRect& rect,
  177.                                 FW_ERenderVerbs renderVerb,
  178.                                 const FW_PInk& ink,
  179.                                 const FW_PStyle& style)
  180. {
  181.     FW_RASTERIZER_PROLOG
  182.     FW_CHECK_RENDER_VERB
  183.     FW_CHECK_INK
  184.     FW_CHECK_STYLE
  185.  
  186.     FW_SPlatformRect plfmRect = gc.LogicalToDevice(rect);
  187.  
  188. #ifdef FW_BUILD_WIN
  189.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, 
  190.                                                     FW_kGeometricShapeWithInvert, 
  191.                                                     renderVerb);
  192.     
  193.     HDC hDC = *device;
  194.     if (frameBrush)
  195.     {
  196.         int penSizeX = device->fPenSize.x;
  197.         int penSizeY = device->fPenSize.y;
  198.  
  199.         device->fGDIBrush.SelectObject(hDC);
  200.         ::PatBlt(hDC, plfmRect.left, plfmRect.top, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  201.         ::PatBlt(hDC, plfmRect.right - penSizeX, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  202.         ::PatBlt(hDC, plfmRect.left, plfmRect.top, penSizeX, plfmRect.bottom - plfmRect.top, PATCOPY);
  203.         ::PatBlt(hDC, plfmRect.left, plfmRect.bottom - penSizeY, plfmRect.right - plfmRect.left, penSizeY, PATCOPY);
  204.     }
  205.     else
  206.     {
  207.         if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite)
  208.         {
  209.             ::InvertRect(hDC, &plfmRect);
  210.         }
  211.         else
  212.         {
  213.             if (renderVerb == FW_kFill)
  214.             {
  215.                 plfmRect.right++;
  216.                 plfmRect.bottom++;
  217.             }
  218.                 
  219.             ::Rectangle(hDC, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  220.         }
  221.     }
  222. #endif
  223. #ifdef FW_BUILD_MAC
  224.     FW_Boolean styleIsDash = MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  225.  
  226.     if (renderVerb == FW_kFrame)
  227.     {
  228.         if (styleIsDash)
  229.         {
  230.             FW_CMacDashDraw draw(style->GetDashStyle());
  231.  
  232.             ::MoveTo(plfmRect.left, plfmRect.top);
  233.             draw.LineTo(plfmRect.right - 1, plfmRect.top);
  234.             draw.LineTo(plfmRect.right - 1, plfmRect.bottom - 1);
  235.             draw.LineTo(plfmRect.left, plfmRect.bottom - 1);
  236.             draw.LineTo(plfmRect.left, plfmRect.top);
  237.         }
  238.         else
  239.         {
  240.             ::FrameRect(&plfmRect);
  241.         }
  242.     }
  243.     else
  244.     {
  245.         switch (ink->GetTransferMode())
  246.         {
  247.             case FW_kErase:
  248.                 ::EraseRect(&plfmRect);
  249.                 break;
  250.  
  251.             case FW_kHilite:
  252.                 FW_CGraphicDevice::SetHiliteMode();
  253.                 // fall-through
  254.  
  255.             case FW_kInvert:
  256.                 ::InvertRect(&plfmRect);
  257.                 break;
  258.                 
  259.             default:
  260.                 ::PaintRect(&plfmRect);            
  261.         }
  262.     }
  263. #endif
  264. }
  265.  
  266. //----------------------------------------------------------------------------------------
  267. //    FW_CPrivRasterizer::RenderOval
  268. //----------------------------------------------------------------------------------------
  269.  
  270. void FW_CPrivRasterizer::RenderOval(FW_CGraphicContext& gc,
  271.                                     const FW_CRect& rect,
  272.                                     FW_ERenderVerbs renderVerb,
  273.                                     const FW_PInk& ink,
  274.                                     const FW_PStyle& style)
  275. {
  276.     FW_RASTERIZER_PROLOG
  277.     FW_CHECK_RENDER_VERB
  278.     FW_CHECK_INK
  279.     FW_CHECK_STYLE
  280.  
  281.     FW_SPlatformRect plfmRect = gc.LogicalToDevice(rect);
  282.  
  283. #ifdef FW_BUILD_WIN
  284.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  285.  
  286.     if (frameBrush)
  287.     {
  288.         HRGN hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, plfmRect.right + 1, plfmRect.bottom + 1);
  289.         ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  290.         ::DeleteObject(hrgn);
  291.     }
  292.     else
  293.     {
  294.         if (renderVerb == FW_kFill)
  295.         {
  296.             plfmRect.right++;
  297.             plfmRect.bottom++;
  298.         }
  299.  
  300.         ::Ellipse(*device, plfmRect.left, plfmRect.top, plfmRect.right, plfmRect.bottom);
  301.     }
  302. #endif
  303. #ifdef FW_BUILD_MAC
  304.     MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  305.     
  306.     if (renderVerb == FW_kFrame)
  307.     {
  308.         ::FrameOval(&plfmRect);
  309.     }
  310.     else
  311.     {
  312.         switch (ink->GetTransferMode())
  313.         {
  314.             case FW_kErase:
  315.                 ::EraseOval(&plfmRect);
  316.                 break;
  317.             case FW_kHilite:
  318.                 FW_CGraphicDevice::SetHiliteMode();
  319.                 // fall-through
  320.             case FW_kInvert:
  321.                 ::InvertOval(&plfmRect);
  322.                 break;
  323.             default:
  324.                 ::PaintOval(&plfmRect);            
  325.         }
  326.     }
  327. #endif
  328. }
  329.  
  330. //----------------------------------------------------------------------------------------
  331. //    FW_CPrivRasterizer::RenderRoundRect
  332. //----------------------------------------------------------------------------------------
  333.  
  334. void FW_CPrivRasterizer::RenderRoundRect(FW_CGraphicContext& gc,
  335.                                         const FW_CRect& rect,
  336.                                         const FW_CPoint& ovalSize,
  337.                                         FW_ERenderVerbs renderVerb,
  338.                                         const FW_PInk& ink,
  339.                                         const FW_PStyle& style)
  340. {
  341.     FW_RASTERIZER_PROLOG
  342.     FW_CHECK_RENDER_VERB
  343.     FW_CHECK_INK
  344.     FW_CHECK_STYLE
  345.  
  346.     FW_SPlatformRect plfmRect = gc.LogicalToDevice(rect);
  347.     FW_SPlatformPoint plfmOvalSize = gc.LogicalToDevice(ovalSize.x, ovalSize.y);
  348.     
  349. #ifdef FW_BUILD_WIN
  350.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  351.  
  352.     if (frameBrush)
  353.     {
  354.         HRGN hrgn = NULL;
  355.         // There is a bug in Windows. If the size of the round rect is smaller than 1,  we are dead.
  356.         if ((plfmRect.right - plfmRect.left <= 1) || (plfmRect.bottom - plfmRect.top <= 1))
  357.             hrgn = ::CreateEllipticRgn(plfmRect.left, plfmRect.top, 
  358.                                         plfmRect.right + 1, plfmRect.bottom + 1);
  359.         else
  360.             hrgn = ::CreateRoundRectRgn(plfmRect.left, plfmRect.top, 
  361.                                         plfmRect.right + 1, plfmRect.bottom + 1, 
  362.                                         plfmOvalSize.x, plfmOvalSize.y);
  363.                                         
  364.         ::FrameRgn(*device, hrgn, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  365.         ::DeleteObject(hrgn);
  366.     }
  367.     else
  368.     {
  369.         if (renderVerb == FW_kFill)
  370.         {
  371.             plfmRect.right++;
  372.             plfmRect.bottom++;
  373.         }
  374.     
  375.         ::RoundRect(*device, 
  376.                     plfmRect.left, plfmRect.top, 
  377.                     plfmRect.right, plfmRect.bottom,
  378.                     plfmOvalSize.x, plfmOvalSize.y);
  379.     }
  380. #endif
  381. #ifdef FW_BUILD_MAC
  382.     GrafPtr curGrafPtr;        // [KVV] Debugging
  383.     GetPort(&curGrafPtr);
  384.  
  385.     MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  386.     
  387.     if (renderVerb == FW_kFrame)
  388.     {
  389.         ::FrameRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  390.     }
  391.     else
  392.     {
  393.         switch (ink->GetTransferMode())
  394.         {
  395.             case FW_kErase:
  396.                 ::EraseRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  397.                 break;
  398.             case FW_kHilite:
  399.                 FW_CGraphicDevice::SetHiliteMode();
  400.             case FW_kInvert:
  401.                 ::InvertRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);
  402.                 break;
  403.             default:
  404.                 ::PaintRoundRect(&plfmRect, plfmOvalSize.h, plfmOvalSize.v);            
  405.         }
  406.     }
  407. #endif
  408. }
  409.  
  410. //----------------------------------------------------------------------------------------
  411. //    FW_CPrivRasterizer::RenderArc
  412. //----------------------------------------------------------------------------------------
  413.  
  414. void FW_CPrivRasterizer::RenderArc(FW_CGraphicContext& gc,
  415.                                 const FW_CRect& rect, 
  416.                                 short startAngle, short arcAngle,
  417.                                 FW_ERenderVerbs renderVerb,
  418.                                 const FW_PInk& ink,
  419.                                 const FW_PStyle& style)
  420. {    
  421.     FW_RASTERIZER_PROLOG
  422.     FW_CHECK_RENDER_VERB
  423.     FW_CHECK_INK
  424.     FW_CHECK_STYLE
  425.  
  426.     FW_SPlatformRect arcRect = gc.LogicalToDevice(rect);
  427.  
  428. #ifdef FW_BUILD_WIN    
  429.     short angle1 = startAngle;
  430.     
  431.     // Normalize the start angle
  432.     angle1 = angle1 % 360;
  433.     if (angle1 < 0)
  434.         angle1 += 360;
  435.         
  436.     // Compute and normalize the end angle
  437.     short angle2 = angle1 + arcAngle;
  438.     if (arcAngle < 0)
  439.     {
  440.         short temp = angle1;
  441.         angle1 = angle2;
  442.         angle2 = temp;
  443.     }
  444.  
  445.     FW_SPlatformPoint endPoint, startPoint;
  446.     FW_PrivCalcArcPoints(arcRect, angle1, endPoint);        // on Windows, arc and pie are drawn counterclockwise
  447.     FW_PrivCalcArcPoints(arcRect, angle2, startPoint);
  448.  
  449.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  450.  
  451.     if (renderVerb == FW_kFrame)
  452.     {
  453.         if(frameBrush)
  454.         {
  455.             ODRgnHandle rgnHandle = ::FW_CreateArcRegion(arcRect, startAngle, arcAngle);
  456.             ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  457.             ::FW_DisposeRegion(rgnHandle);
  458.         }
  459.         else
  460.         {
  461.             ::Arc(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  462.                 startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  463.         }
  464.     }
  465.     else
  466.     {
  467.         arcRect.right++;
  468.         arcRect.bottom++;
  469.         ::Pie(*device, arcRect.left, arcRect.top, arcRect.right, arcRect.bottom,
  470.                 startPoint.x, startPoint.y, endPoint.x, endPoint.y);
  471.     }
  472. #endif
  473. #ifdef FW_BUILD_MAC
  474.     MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);
  475.     
  476.     if (renderVerb == FW_kFrame)
  477.     {
  478.         ::FrameArc(&arcRect, startAngle, arcAngle);
  479.     }
  480.     else
  481.     {
  482.         switch (ink->GetTransferMode())
  483.         {
  484.             case FW_kErase:
  485.                 ::EraseArc(&arcRect, startAngle, arcAngle);
  486.                 break;
  487.             case FW_kHilite:
  488.                 FW_CGraphicDevice::SetHiliteMode();
  489.             case FW_kInvert:
  490.                 ::InvertArc(&arcRect, startAngle, arcAngle);
  491.                 break;
  492.             default:
  493.                 ::PaintArc(&arcRect, startAngle, arcAngle);            
  494.         }
  495.     }
  496. #endif
  497. }
  498.  
  499. //----------------------------------------------------------------------------------------
  500. //     FW_CPrivRasterizer::RenderLine
  501. //----------------------------------------------------------------------------------------
  502.  
  503. void FW_CPrivRasterizer::RenderLine(FW_CGraphicContext& gc,
  504.                                     const FW_CPoint& start, 
  505.                                     const FW_CPoint& end,
  506.                                     FW_ERenderVerbs renderVerb,
  507.                                     const FW_PInk& ink,
  508.                                     const FW_PStyle& style)
  509. {
  510.     FW_RASTERIZER_PROLOG
  511.     FW_CHECK_RENDER_VERB
  512.     FW_CHECK_INK
  513.     FW_CHECK_STYLE
  514.  
  515.     FW_SPlatformPoint plfmStart = gc.LogicalToDevice(start);
  516.     FW_SPlatformPoint plfmEnd = gc.LogicalToDevice(end);
  517.  
  518. #ifdef FW_BUILD_WIN
  519.     HDC hDC = device->GetPlatformCanvas();
  520.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, FW_kFrame);
  521.     
  522.     if (frameBrush)
  523.     {
  524.         int penSizeX = device->fPenSize.x;
  525.         int penHalfX = penSizeX / 2;
  526.         int penSizeY = device->fPenSize.y;
  527.         int penHalfY = penSizeY / 2;
  528.         if (plfmStart.x == plfmEnd.x)
  529.         {
  530.             device->fGDIBrush.SelectObject(hDC);
  531.             ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, penSizeX, plfmEnd.y - plfmStart.y, PATCOPY);
  532.         }
  533.         else if (plfmStart.y == plfmEnd.y)
  534.         {
  535.             device->fGDIBrush.SelectObject(hDC);
  536.             ::PatBlt(hDC, plfmStart.x - penHalfX, plfmStart.y - penHalfY, plfmEnd.x - plfmStart.x, penSizeY, PATCOPY);
  537.         }
  538.         else
  539.         {
  540.             HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(plfmStart), FW_CPoint(plfmEnd), FW_CPoint(device->fPenSize));        
  541.             ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  542.             ::DeleteObject(hRgn);
  543.         }
  544.     }
  545.     else
  546.     {
  547.         ::MoveToEx(hDC, plfmStart.x, plfmStart.y, NULL);
  548.         ::LineTo(hDC, plfmEnd.x, plfmEnd.y);
  549.     }
  550. #endif
  551. #ifdef FW_BUILD_MAC
  552.     FW_Boolean styleIsDash = MacSelectInkAndStyle(device,
  553.                         FW_kLineShape,
  554.                         FW_kFrame,                        // We never use FW_kFill for lines
  555.                         ink,
  556.                         style);    
  557.  
  558.     short halfPenh = FW_QDGlobals.thePort->pnSize.h / 2;
  559.     short halfPenv = FW_QDGlobals.thePort->pnSize.v / 2;
  560.     
  561.     ::MoveTo(plfmStart.h - halfPenh, plfmStart.v - halfPenv);
  562.     
  563.     if (styleIsDash && halfPenh == 0 && halfPenv == 0)
  564.     {
  565.         FW_CMacDashDraw draw(style->GetDashStyle());
  566.         draw.LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  567.     }
  568.     else
  569.     {
  570.         ::LineTo(plfmEnd.h - halfPenh, plfmEnd.v - halfPenv);
  571.     }
  572. #endif
  573. }
  574.  
  575. //----------------------------------------------------------------------------------------
  576. //    FW_CPrivRasterizer::RenderRegion
  577. //----------------------------------------------------------------------------------------
  578.  
  579. void FW_CPrivRasterizer::RenderRegion(FW_CGraphicContext& gc,
  580.                                     ODShape* odShape,
  581.                                     FW_ERenderVerbs renderVerb,
  582.                                     const FW_PInk& ink,
  583.                                     const FW_PStyle& style)
  584. {
  585.     FW_RASTERIZER_PROLOG
  586.     FW_CHECK_RENDER_VERB
  587.     FW_CHECK_INK
  588.     FW_CHECK_STYLE
  589.     
  590.     Environment* ev = gc.GetEnvironment();
  591.  
  592.     ODShape* deviceShape = gc.LogicalToDevice(odShape);
  593.     ODRgnHandle rgnHandle = ::FW_GetShapeRegion(ev, deviceShape);
  594.     FW_ASSERT(rgnHandle != NULL);
  595.     
  596. #ifdef FW_BUILD_WIN
  597.     FW_ERenderVerbs localVerb = renderVerb == FW_kFrame ? FW_kFill : renderVerb;
  598.     device->SelectInkAndStyle(ink, style, FW_kGeometricShapeWithInvert, localVerb);
  599.     
  600.     switch (renderVerb)
  601.     {
  602.         case FW_kFrame:
  603.             ::FrameRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device), device->fPenSize.x, device->fPenSize.y);
  604.             break;
  605.  
  606.         case FW_kFill:
  607.             if (ink->GetTransferMode() == FW_kInvert || ink->GetTransferMode() == FW_kHilite)
  608.                 ::InvertRgn(*device, rgnHandle);
  609.             else
  610.                 ::FillRgn(*device, rgnHandle, device->fGDIBrush.GetBrush(*device));
  611.             break;
  612.     }
  613. #endif
  614. #ifdef FW_BUILD_MAC
  615.     MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);        
  616.     
  617.     if (renderVerb == FW_kFrame)
  618.     {
  619.         ::FrameRgn(rgnHandle);
  620.     }
  621.     else
  622.     {
  623.         switch (ink->GetTransferMode())
  624.         {
  625.             case FW_kErase:
  626.                 ::EraseRgn(rgnHandle);
  627.                 break;
  628.             case FW_kXOr:
  629.                 ::InvertRgn(rgnHandle);
  630.                 break;
  631.             default:
  632.                 ::PaintRgn(rgnHandle);            
  633.         }
  634.     }
  635.     
  636. #endif
  637.     deviceShape->Release(ev);
  638. }
  639.  
  640. //----------------------------------------------------------------------------------------
  641. //    FW_CPrivRasterizer::RenderPolygon
  642. //----------------------------------------------------------------------------------------
  643.  
  644. void FW_CPrivRasterizer::RenderPolygon(FW_CGraphicContext& gc,
  645.                                     const FW_PPolygon& polygon,
  646.                                     FW_ERenderVerbs renderVerb,
  647.                                     FW_Boolean autoCloseFrame,
  648.                                     const FW_PInk& ink,
  649.                                     const FW_PStyle& style)
  650. {
  651.     FW_RASTERIZER_PROLOG
  652.     FW_CHECK_RENDER_VERB
  653.     FW_CHECK_INK
  654.     FW_CHECK_STYLE
  655.  
  656. #ifdef FW_BUILD_WIN
  657.     // Convert points to platform points
  658.     unsigned long count = polygon->GetCount();
  659.     const FW_CPoint* points = polygon->GetPoints();
  660.  
  661.     unsigned long plfmCount = count;
  662.     FW_Boolean needClose = FALSE;
  663.     if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  664.     {
  665.         ++ plfmCount;
  666.         needClose = TRUE;
  667.     }
  668.     
  669.     FW_SPlatformPoint* plfmPoints = new FW_SPlatformPoint[plfmCount];
  670.     for(unsigned long i = 0; i < count; i ++)
  671.         plfmPoints[i] = gc.LogicalToDevice(points[i]);
  672.  
  673.     if(needClose)
  674.         plfmPoints[plfmCount - 1] = plfmPoints[0];
  675.  
  676.     // Prepare the graphics device
  677.     FW_Boolean frameBrush = device->SelectInkAndStyle(ink, style, FW_kGeometricShape, renderVerb);
  678.  
  679.     int penSizeX = device->fPenSize.x;
  680.     int penHalfX = penSizeX / 2;
  681.     int penSizeY = device->fPenSize.y;
  682.     int penHalfY = penSizeY / 2;
  683.     
  684.     HDC hDC = *device;
  685.  
  686.     // Render the polygon
  687.     switch (renderVerb)
  688.     {
  689.         case FW_kFrame:
  690.             if(frameBrush)
  691.             {
  692.                 // Doing it like this is way, way faster than creating a polygon
  693.                 // region for the whole thing and framing it
  694.                 FW_SPlatformPoint pt0, pt1;
  695.                 BOOL bBrushSelected = FALSE;
  696.  
  697.                 for(unsigned long p = 0; p < plfmCount - 1; p ++)
  698.                 {
  699.                     pt0 = plfmPoints[p];
  700.                     pt1 = plfmPoints[p + 1];
  701.                     
  702.                     if (pt0.x == pt1.x)
  703.                     {
  704.                         if (!bBrushSelected)
  705.                         {
  706.                             device->fGDIBrush.SelectObject(hDC);
  707.                             bBrushSelected = TRUE;
  708.                         }
  709.  
  710.                         ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, penSizeX, pt1.y - pt0.y, PATCOPY);
  711.                     }
  712.                     else if (pt0.y == pt1.y)
  713.                     {
  714.                         if (!bBrushSelected)
  715.                         {
  716.                             device->fGDIBrush.SelectObject(hDC);
  717.                             bBrushSelected = TRUE;
  718.                         }
  719.  
  720.                         ::PatBlt(hDC, pt0.x - penHalfX, pt0.y - penHalfY, pt1.x - pt0.x, penSizeY, PATCOPY);
  721.                     }
  722.                     else
  723.                     {
  724.                         HRGN hRgn = ::FW_CreateLineRegion(FW_CPoint(pt0), FW_CPoint(pt1), FW_CPoint(device->fPenSize));
  725.                         ::FillRgn(hDC, hRgn, device->fGDIBrush.GetBrush(hDC));
  726.                         ::DeleteObject(hRgn);
  727.                     }
  728.                 }
  729.             }
  730.             else
  731.             {
  732.                 ::Polyline(hDC, plfmPoints, plfmCount);
  733.             }
  734.             break;
  735.  
  736.         case FW_kFill:
  737.             ::Polygon(hDC, plfmPoints, plfmCount);
  738.             break;
  739.     }
  740.     
  741.     delete[] plfmPoints;
  742. #endif
  743. #ifdef FW_BUILD_MAC
  744.     // Create a polygon
  745.     GrafPtr savePort;
  746.     ::GetPort(&savePort);
  747.     ::SetPort(FW_gScratchWindow);
  748.     PolyHandle polyHandle = ::OpenPoly();
  749.     
  750.     if(polyHandle == NULL)
  751.     {
  752.         ::SetPort(savePort);
  753.         FW_Failure(FW_xMemoryExhausted);
  754.     }
  755.  
  756.     unsigned long count = polygon->GetCount();
  757.     const FW_CPoint* points = polygon->GetPoints();
  758.  
  759.     FW_SPlatformPoint plfmPoint;
  760.     plfmPoint = gc.LogicalToDevice(points[0]);
  761.     ::MoveTo(plfmPoint.h, plfmPoint.v);
  762.  
  763.     for(unsigned long i = 1; i < count; i ++)
  764.     {
  765.         plfmPoint = gc.LogicalToDevice(points[i]);
  766.         ::LineTo(plfmPoint.h, plfmPoint.v);
  767.     }
  768.     
  769.     // Close the polygon if needed
  770.     if(renderVerb == FW_kFrame && autoCloseFrame && points[0] != points[count - 1])
  771.     {
  772.         plfmPoint = gc.LogicalToDevice(points[0]);
  773.         ::LineTo(plfmPoint.h, plfmPoint.v);
  774.     }
  775.  
  776.     ::ClosePoly();
  777.     ::SetPort(savePort);
  778.  
  779.     // Prepare the grafport
  780.     FW_Boolean styleIsDash = MacSelectInkAndStyle(device, FW_kGeometricShape, renderVerb, ink, style);        
  781.     
  782.     // Render the polygon
  783.     if (renderVerb == FW_kFrame)
  784.     {
  785.         if (styleIsDash)
  786.         {
  787.             FW_CMacDashDraw draw(style->GetDashStyle());
  788.             short nPolyCount = ((*polyHandle)->polySize - 10) / sizeof(Point);
  789.             ::MoveTo((*polyHandle)->polyPoints[0].h, (*polyHandle)->polyPoints[0].v);
  790.             for (short n = 1; n < nPolyCount; ++ n)
  791.                 draw.LineTo((*polyHandle)->polyPoints[n].h, (*polyHandle)->polyPoints[n].v);
  792.         }
  793.         else
  794.         {
  795.             ::FramePoly(polyHandle);
  796.         }
  797.     }
  798.     else
  799.     {
  800.         switch (ink->GetTransferMode())
  801.         {
  802.             case FW_kErase:
  803.                 ::ErasePoly(polyHandle);
  804.                 break;
  805.             case FW_kXOr:
  806.                 ::InvertPoly(polyHandle);
  807.                 break;
  808.             default:
  809.                 ::PaintPoly(polyHandle);            
  810.         }
  811.     }
  812.  
  813.     ::KillPoly(polyHandle);
  814. #endif
  815. }
  816.  
  817. //----------------------------------------------------------------------------------------
  818. //    FW_CPrivRasterizer::TextExtent
  819. //----------------------------------------------------------------------------------------
  820.  
  821. void FW_CPrivRasterizer::TextExtent(FW_CGraphicContext& gc,
  822.                                     FW_CPrivTextBuffer *textBuffer,
  823.                                     const FW_PFont& font, 
  824.                                     FW_CPoint& textExtent)
  825. {
  826.     FW_RASTERIZER_PROLOG
  827.     FW_CHECK_FONT
  828.  
  829.     if (textBuffer->IsDone())
  830.     {
  831.         textExtent = FW_kZeroPoint;
  832.         return;
  833.     }
  834.  
  835.     device->SelectFont(font, TRUE);
  836.     
  837.     // ----- TextExtent only cares about the first line -----    
  838.     FW_CharacterCount charCount = textBuffer->GetCurrentLineLength();
  839.     const FW_Char* text = (const FW_Char*) textBuffer->GetCurrentLine();
  840.  
  841. #ifdef FW_BUILD_WIN
  842.     SIZE size;
  843.     ::GetTextExtentPoint32(*device, text, charCount, &size);
  844.     FW_SPlatformPoint plfmExtent(size.cx, size.cy);
  845. #endif
  846. #ifdef FW_BUILD_MAC
  847.     FontInfo fi;
  848.     ::GetFontInfo(&fi);
  849.     
  850.     FW_SPlatformPoint plfmExtent(
  851.             ::TextWidth(text, 0, charCount),
  852.             fi.ascent + fi.descent);
  853. #endif
  854.  
  855.     textExtent = gc.DeviceToLogical(plfmExtent.X(), plfmExtent.Y());
  856. }
  857.  
  858. //----------------------------------------------------------------------------------------
  859. //    FW_CPrivRasterizer::TextBoxSize
  860. //----------------------------------------------------------------------------------------
  861.  
  862. void FW_CPrivRasterizer::TextBoxSize(FW_CGraphicContext& gc,
  863.                                     FW_CPrivTextBuffer *textBuffer, 
  864.                                     const FW_PFont& font,
  865.                                     FW_TextBoxOptions options,
  866.                                     FW_CRect& textBox)
  867. {
  868.     FW_RASTERIZER_PROLOG
  869.     FW_CHECK_FONT
  870.     
  871.     FW_ASSERT((const void*)font != NULL);
  872.     FW_ASSERT(textBuffer != NULL);
  873.  
  874.     FW_SPlatformRect plfmBox = gc.LogicalToDevice(textBox);
  875.  
  876.     if (textBuffer->IsDone())
  877.     {
  878.         plfmBox.bottom = plfmBox.top;
  879.     }
  880.     else
  881.     {
  882.         device->SelectFont(font, TRUE);                    // TRUE: scale
  883.         plfmBox.bottom = PrivTextBox(device, textBuffer, plfmBox, options, FALSE, font);    // FALSE: don't draw
  884.     }
  885.  
  886.     FW_CPoint textBoxSize = gc.DeviceToLogical(plfmBox.right, plfmBox.bottom);
  887.     textBox.right    = textBox.left + textBoxSize.x;
  888.     textBox.bottom    = textBox.top  + textBoxSize.y;
  889. }
  890.  
  891. //----------------------------------------------------------------------------------------
  892. //    FW_CPrivRasterizer::RenderText
  893. //----------------------------------------------------------------------------------------
  894.  
  895. void FW_CPrivRasterizer::RenderText(FW_CGraphicContext& gc,
  896.                                     FW_CPrivTextBuffer *textBuffer,
  897.                                       const FW_CPoint& position,
  898.                                       FW_TextAlignment textAlignment,
  899.                                     FW_ERenderVerbs renderVerb,
  900.                                     const FW_PInk& ink,
  901.                                     const FW_PFont& font)
  902. {    
  903.     FW_RASTERIZER_PROLOG
  904.     FW_CHECK_RENDER_VERB
  905.     FW_CHECK_FONT
  906.     FW_CHECK_INK
  907.  
  908.     FW_ASSERT(textBuffer != NULL);
  909.     if (textBuffer->IsDone())    // No text to draw
  910.         return;
  911.     
  912.     FW_SPlatformPoint plfmPos = gc.LogicalToDevice(position);
  913.  
  914.     // ----- RenderText only cares about the first line -----    
  915.     FW_CharacterCount charCount = textBuffer->GetCurrentLineLength();
  916.     const FW_Char* text = (const FW_Char*) textBuffer->GetCurrentLine();
  917.     
  918. #ifdef FW_BUILD_WIN
  919.     device->SelectInkAndFont(ink, font);
  920.         
  921.     // ----- Set the text alignment - always use TA_UPDATECP (see below)
  922.     TEXTMETRIC tm;
  923.     UINT newAlign = TA_UPDATECP;
  924.     
  925.     switch (textAlignment & FW_kTextAlignPrivVertAlignMask)
  926.     {
  927.         case FW_kTextAlignTop:
  928.             newAlign |= TA_TOP;
  929.             break;
  930.             
  931.         case FW_kTextAlignBottom:
  932.             newAlign |= TA_BOTTOM;
  933.             break;
  934.             
  935.         case FW_kTextAlignVCenter:
  936.             ::GetTextMetrics(*device, &tm);
  937.             plfmPos.y -= (tm.tmHeight - tm.tmInternalLeading) / 2;
  938.             break;
  939.             
  940.         case FW_kTextAlignBaseLine:
  941.             newAlign |= TA_BASELINE;
  942.             break;
  943.     }
  944.  
  945.     switch (textAlignment & FW_kTextAlignPrivHorzAlignMask)
  946.     {
  947.         case FW_kTextAlignLeft:
  948.             newAlign |= TA_LEFT;
  949.             break;
  950.             
  951.         case FW_kTextAlignRight:
  952.             newAlign |= TA_RIGHT;
  953.             break;
  954.             
  955.         case FW_kTextAlignHCenter:
  956.             newAlign |= TA_CENTER;
  957.             break;
  958.     }
  959.     
  960.     // It is necessary to use TA_UPDATECP because the next call may want to use
  961.     //    FW_kTextAlignUseCurrentPos.  However, TA_UPDATECP also means "use CP", so
  962.     //    if this is not what the user wants, we should move to the right pos first
  963.  
  964.     if((textAlignment & FW_kTextAlignPrivUsePosMask) == FW_kTextAlignUseSpecifiedPos)
  965.         ::MoveToEx(*device, plfmPos.x, plfmPos.y, NULL);
  966.  
  967.     ::SetTextAlign(*device, newAlign);
  968.     ::TextOut(*device,
  969.             0, 0,        // we use TA_UPDATECP, remember?
  970.             text,
  971.             charCount);
  972.             
  973.     ::SetTextAlign(*device, TA_LEFT | TA_TOP | TA_NOUPDATECP);        // restore the flags
  974. #endif
  975. #ifdef FW_BUILD_MAC
  976.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  977.     device->SelectFont(font, TRUE);        // SetInGrafPort called by SelectFont
  978.  
  979.     // ----- The Mac only knows to draw text from the baseline, so we need to do some adjustment
  980.     FW_SPlatformPoint plfmTextPos = MacCalcTextPosition(device, charCount, (const char*) text, textAlignment, plfmPos);
  981.     
  982.     // ----- Draw the text
  983.     ::MoveTo(plfmTextPos.h, plfmTextPos.v);
  984.     ::DrawText(text, 0, charCount);
  985.  
  986.     // ----- StrikeOut if necessary
  987.     if (font->GetFontStyle() & FW_kStrikeOut)
  988.         MacStrikeOut(device, plfmTextPos.h, plfmTextPos.v);
  989. #endif
  990. }
  991.  
  992. //----------------------------------------------------------------------------------------
  993. //    FW_CTextBoxShape::PrivTextBox
  994. //----------------------------------------------------------------------------------------
  995.  
  996. FW_PlatformCoordinate FW_CPrivRasterizer::PrivTextBox(FW_CGraphicDevice* device,
  997.                                                     FW_CPrivTextBuffer *textBuffer, 
  998.                                                     const FW_SPlatformRect& box,
  999.                                                     FW_TextBoxOptions options,
  1000.                                                     FW_Boolean draw,
  1001.                                                     const FW_PFont& font)
  1002. {
  1003.     // ----- Check options for consistency
  1004.     FW_TextBoxOptions opt = options;
  1005.  
  1006.     if (!draw)
  1007.         opt &= ~FW_kTextBoxClipToBox;
  1008.     
  1009.     if ((opt & FW_kTextBoxSingleLine) != 0)
  1010.     {
  1011.         opt &= ~FW_kTextBoxWordWrap;
  1012.         opt &= ~FW_kTextBoxWordBreak;
  1013.     }
  1014.     
  1015.     if ((opt & FW_kTextBoxWordWrap) != 0)
  1016.     {
  1017.         opt &= ~FW_kTextBoxJustifyBottom;
  1018.         opt &= ~FW_kTextBoxJustifyVCenter;
  1019.     }
  1020.  
  1021.     FW_CharacterPosition segStart;        // start of the current string segment
  1022.     FW_CharacterCount segLen;            // its length (charcter count)
  1023.     FW_PlatformCoordinate actualWidth;    // its actual width (pixels)
  1024.     FW_PlatformCoordinate maxWidth = box.right - box.left;
  1025.  
  1026.     FW_Boolean bClip = (opt & FW_kTextBoxClipToBox) != 0;
  1027.  
  1028. #ifdef FW_BUILD_WIN
  1029.     // ----- Set the clipping region if we need to
  1030.     HDC hDC = device->GetPlatformCanvas();
  1031.     int savedDC = 0;
  1032.     if (bClip)
  1033.     {
  1034.         savedDC = ::SaveDC(hDC);
  1035.         ::IntersectClipRect(hDC, 
  1036.                             box.left, box.top, 
  1037.                             box.right, box.bottom);
  1038.     }
  1039.  
  1040.     // ----- Get the font height
  1041.     TEXTMETRIC textMetric;
  1042.     ::GetTextMetrics(hDC, &textMetric);
  1043.     short fontHeight = textMetric.tmHeight + textMetric.tmExternalLeading;
  1044.  
  1045.     short drawPosY = box.top;
  1046.     short drawPosX = box.left;
  1047. #endif
  1048. #ifdef FW_BUILD_MAC
  1049.     // ----- Set the clipping region if we need to
  1050.     RgnHandle oldClipRgn = 0;
  1051.     if (bClip)
  1052.     {
  1053.         oldClipRgn = device->GetClip();
  1054.         device->IntersectClipRect(box);
  1055.     }
  1056.  
  1057.     // ----- Get the font height -----
  1058.     FontInfo fi;
  1059.     ::GetFontInfo(&fi);
  1060.     short fontHeight = fi.ascent + fi.descent + fi.leading;
  1061.  
  1062.     short drawPosY = box.top + fi.ascent;
  1063.     short drawPosX = box.left;
  1064.     
  1065.     FW_Boolean bIsStrikeOut = font->GetFontStyle() & FW_kStrikeOut;
  1066. #endif
  1067.  
  1068.     // ----- Check vertical jusitficaiton
  1069.     switch (opt & FW_kTextBoxPrivVertJusificationMask)
  1070.     {
  1071.     case FW_kTextBoxJustifyVCenter:
  1072. #ifdef FW_BUILD_WIN
  1073.         drawPosY = (box.top + box.bottom - fontHeight) / 2;
  1074. #endif
  1075. #ifdef FW_BUILD_MAC
  1076.         drawPosY = (box.top + box.bottom + fi.ascent - fi.descent) / 2;
  1077. #endif
  1078.         break;
  1079.         
  1080.     case FW_kTextBoxJustifyBottom:
  1081.         drawPosY = box.bottom - fontHeight;
  1082.         break;
  1083.     }
  1084.  
  1085.     // ----- Draw string segments one by one
  1086.     FW_Boolean wordWrap = (opt & FW_kTextBoxWordWrap) != 0;
  1087.     FW_Boolean wordBreak = (opt & FW_kTextBoxWordBreak) != 0;
  1088.     FW_Boolean reachedBottom = FALSE;
  1089.     while (!reachedBottom && !textBuffer->IsDone())
  1090.     {
  1091.         const FW_Char* line = (const FW_Char*) textBuffer->GetCurrentLine();
  1092.         FW_CharacterCount lineLength = textBuffer->GetCurrentLineLength();
  1093.         
  1094.         // ----- Draw the current segment
  1095.         while (!reachedBottom && PrivGetStringSegment(*device, line, lineLength,
  1096.             segStart, segLen, maxWidth, actualWidth, wordWrap, wordBreak))
  1097.         {
  1098.             // ----- Check horizontal jusitficaiton
  1099.             switch (opt & FW_kTextBoxPrivHorzJusificationMask)
  1100.             {
  1101.             case FW_kTextAlignHCenter:
  1102.                 drawPosX = (box.left + box.right - actualWidth) / 2;
  1103.                 break;
  1104.             
  1105.             case FW_kTextAlignRight:
  1106.                 drawPosX = box.right - actualWidth;
  1107.                 break;
  1108.             }
  1109.  
  1110.             if (draw)
  1111.             {
  1112.                 // ----- Draw the next line -----
  1113. #ifdef FW_BUILD_WIN
  1114.                 ::TextOut(hDC, drawPosX, drawPosY, line + segStart, segLen);
  1115. #endif
  1116. #ifdef FW_BUILD_MAC
  1117.                 ::MoveTo(drawPosX, drawPosY);
  1118.                 ::DrawText((Ptr)line, segStart, segLen);
  1119.     
  1120.                 // ----- StrikeOut if necessary -----
  1121.                 if (bIsStrikeOut)
  1122.                     MacStrikeOut(device, drawPosX, drawPosY);
  1123. #endif
  1124.             }
  1125.             
  1126.             drawPosY += fontHeight;        // Move one line down
  1127.             line += segLen + segStart;    // move on to the next segment
  1128.             lineLength -= segLen + segStart;
  1129.             
  1130.             // see if we've gotten to the bottom of the rectangle and need not to continue
  1131.             reachedBottom = bClip && (drawPosY > box.bottom);
  1132.         }
  1133.         
  1134.         if (!reachedBottom)
  1135.             textBuffer->GetNextLine();
  1136.     }
  1137.  
  1138.     // ----- Restore clipping region
  1139. #ifdef FW_BUILD_WIN
  1140.     if (savedDC != 0)
  1141.         ::RestoreDC(*device, savedDC);
  1142. #endif
  1143. #ifdef FW_BUILD_MAC
  1144.     if (oldClipRgn != NULL)
  1145.     {
  1146.         ::SetClip(oldClipRgn);
  1147.         ::DisposeRgn(oldClipRgn);
  1148.     }
  1149.     
  1150. #endif
  1151.  
  1152.     // ----- Return the result ----
  1153. #ifdef FW_BUILD_WIN
  1154.     return drawPosY;
  1155. #endif
  1156. #ifdef FW_BUILD_MAC
  1157.     return drawPosY - fi.ascent;
  1158. #endif
  1159. }
  1160.  
  1161. //----------------------------------------------------------------------------------------
  1162. //    FW_CTextBoxShape::RenderTextBox
  1163. //----------------------------------------------------------------------------------------
  1164.  
  1165. FW_CFixed FW_CPrivRasterizer::RenderTextBox(FW_CGraphicContext& gc,
  1166.                                             FW_CPrivTextBuffer *textBuffer, 
  1167.                                             const FW_CRect& box,
  1168.                                             FW_TextBoxOptions options,
  1169.                                             FW_ERenderVerbs renderVerb,
  1170.                                             const FW_PInk& ink,
  1171.                                             const FW_PFont& font)
  1172. {
  1173.     FW_RASTERIZER_PROLOG
  1174.     FW_CHECK_FONT
  1175.     FW_CHECK_INK
  1176.     
  1177.     FW_ASSERT(textBuffer != NULL);
  1178.     if (renderVerb == FW_kNoRendering || textBuffer->IsDone())
  1179.         return box.top;
  1180.  
  1181.     FW_SPlatformRect plfmBox = gc.LogicalToDevice(box);
  1182.  
  1183. #ifdef FW_BUILD_WIN
  1184.     device->SelectInkAndFont(ink, font);
  1185. #endif
  1186. #ifdef FW_BUILD_MAC
  1187.     device->SelectInk(ink, FW_kTypographicShape, FW_kFill);
  1188.     device->SelectFont(font, TRUE);    // SetInGrafPort called by SelectFont
  1189. #endif
  1190.  
  1191.     FW_PlatformCoordinate bottom = PrivTextBox(device, textBuffer, plfmBox, options, TRUE, font);
  1192.  
  1193.     if (bottom != plfmBox.bottom)
  1194.     {
  1195.         FW_SPlatformPoint pt(0, bottom);
  1196.         FW_CPoint cPt = gc.DeviceToLogical(pt);
  1197.         return cPt.y;
  1198.     }
  1199.  
  1200.     return box.bottom;
  1201. }
  1202.  
  1203. //----------------------------------------------------------------------------------------
  1204. //    FW_CPrivRasterizer::RenderPicture
  1205. //----------------------------------------------------------------------------------------
  1206.  
  1207. void FW_CPrivRasterizer::RenderPicture(FW_CGraphicContext& gc,
  1208.                                     FW_PPicture picture,
  1209.                                     const FW_CRect& dstRect,
  1210.                                     FW_ERenderVerbs renderVerb)
  1211. {
  1212.     FW_RASTERIZER_PROLOG
  1213.     FW_CHECK_RENDER_VERB
  1214.  
  1215.     FW_ASSERT((const void*)picture != NULL);
  1216.     FW_PlatformPict pict = picture->GetPlatformPict();
  1217.     FW_SPlatformRect plfmRect = gc.LogicalToDevice(dstRect);
  1218.  
  1219. #ifdef FW_BUILD_WIN
  1220.     ::PlayEnhMetaFile(*device, pict, &plfmRect);
  1221. #endif
  1222. #ifdef FW_BUILD_MAC
  1223.     ::DrawPicture(picture->GetPlatformPict(), &plfmRect);
  1224. #endif
  1225. }
  1226.  
  1227. //----------------------------------------------------------------------------------------
  1228. //    FW_CPrivRasterizer::RenderBitmap
  1229. //----------------------------------------------------------------------------------------
  1230.  
  1231. void FW_CPrivRasterizer::RenderBitmap(FW_CGraphicContext& gc,
  1232.                                     FW_PBitmap bitmap,
  1233.                                     const FW_CRect& srcRect,
  1234.                                     const FW_CRect& dstRect,
  1235.                                     FW_ERenderVerbs renderVerb,
  1236.                                     const FW_PInk& ink)
  1237. {
  1238.     FW_RASTERIZER_PROLOG
  1239.     FW_CHECK_RENDER_VERB
  1240.  
  1241.     FW_ASSERT((const void*)bitmap != NULL);
  1242.         
  1243.     // Convert source and destination rectangles
  1244.     FW_SPlatformRect plfmDstRect = gc.LogicalToDevice(dstRect);
  1245.     FW_SPlatformRect plfmSrcRect = srcRect;
  1246.  
  1247. #ifdef FW_BUILD_WIN
  1248.     ::SetTextColor(*device, *ink->GetForeColor());
  1249.     ::SetBkColor(*device, *ink->GetBackColor());
  1250.     
  1251.     HDC hDC = *device;
  1252.  
  1253.     HBITMAP plfmBitmap = bitmap->GetPlatformBitmap();
  1254.  
  1255.     HDC memoryDC = ::CreateCompatibleDC(*device);
  1256.     HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, plfmBitmap);
  1257.     
  1258.     HPALETTE hPal = bitmap->GetPalette();
  1259.     HPALETTE hPalOld = NULL;
  1260.     if (hPal != NULL)
  1261.     {
  1262.         hPalOld = ::SelectPalette(hDC, hPal, FALSE);
  1263.         ::RealizePalette(hDC);
  1264.     }
  1265.  
  1266.     ::StretchBlt(hDC,
  1267.                 plfmDstRect.left,
  1268.                 plfmDstRect.top,
  1269.                 plfmDstRect.right - plfmDstRect.left,
  1270.                 plfmDstRect.bottom - plfmDstRect.top,
  1271.                 memoryDC,
  1272.                 plfmSrcRect.left, 
  1273.                 plfmSrcRect.top,
  1274.                 plfmSrcRect.right - plfmSrcRect.left,
  1275.                 plfmSrcRect.bottom - plfmSrcRect.top,
  1276.                 WinConvertRasterOp(ink->GetTransferMode()));
  1277.  
  1278.     if (hPalOld)
  1279.         ::SelectPalette(hDC, hPalOld, TRUE);
  1280.  
  1281.     ::SelectObject(memoryDC, oldBitmap);
  1282.     ::DeleteDC(memoryDC);
  1283. #endif
  1284. #ifdef FW_BUILD_MAC
  1285.     device->SelectInk(ink, FW_kImageShape, FW_kFill);    // Never use FW_kFrame for bitmap
  1286.     device->SetInGrafPort();
  1287.  
  1288.     PixMapHandle pmh = bitmap->MacLockPixels();
  1289.     ::CopyBits((BitMap*)*pmh, &FW_QDGlobals.thePort->portBits, 
  1290.                 &plfmSrcRect, &plfmDstRect, 
  1291.                 ink->GetTransferMode(), NULL);
  1292.     bitmap->MacUnlockPixels();
  1293. #endif
  1294. }
  1295.  
  1296. //----------------------------------------------------------------------------------------
  1297. //    FW_CPrivRasterizer::RenderIcon
  1298. //----------------------------------------------------------------------------------------
  1299.  
  1300. void FW_CPrivRasterizer::RenderIcon(FW_CGraphicContext& gc,
  1301.                                   const FW_PIcon& icon,
  1302.                                   const FW_CRect& rect,
  1303.                                   FW_RenderIconOptions options,
  1304.                                   FW_ERenderVerbs renderVerb)
  1305. {
  1306.     FW_RASTERIZER_PROLOG
  1307.     FW_CHECK_RENDER_VERB
  1308.  
  1309.     FW_ASSERT((const void*)icon != NULL);
  1310.         
  1311.     FW_CPoint iconSize;
  1312.     icon->GetIconSize(iconSize);
  1313.     
  1314.     short xSize = iconSize.IntX(), ySize = iconSize.IntY();
  1315.     
  1316.     FW_SPlatformRect plfmDstRect = gc.LogicalToDevice(rect);
  1317.     
  1318.     if(options != FW_kIconScaleToFit)
  1319.     {
  1320.         // Horizontal alignment
  1321.         switch((options & FW_kIconPrivHorzMask))
  1322.         {
  1323.         case FW_kIconAlignCenter:
  1324.             plfmDstRect.left = (plfmDstRect.right + plfmDstRect.left - xSize) / 2;
  1325.             // fall-through
  1326.  
  1327.         case FW_kIconAlignLeft:
  1328.             plfmDstRect.right = plfmDstRect.left + xSize;
  1329.             break;
  1330.  
  1331.         case FW_kIconAlignRight:
  1332.             plfmDstRect.left = plfmDstRect.right - xSize;
  1333.             break;
  1334.         }
  1335.         
  1336.         // Vertical alignment
  1337.         switch((options & FW_kIconPrivVertMask))
  1338.         {
  1339.         case FW_kIconAlignVCenter:
  1340.             plfmDstRect.top = (plfmDstRect.top + plfmDstRect.bottom - ySize) / 2;
  1341.             // fall-through
  1342.  
  1343.         case FW_kIconAlignTop:
  1344.             plfmDstRect.bottom = plfmDstRect.top + ySize;
  1345.             break;
  1346.  
  1347.         case FW_kIconAlignBottom:
  1348.             plfmDstRect.top = plfmDstRect.bottom - ySize;
  1349.             break;
  1350.         }
  1351.     }
  1352.     
  1353.     FW_PlatformIcon hIcon = icon->GetPlatformIcon();
  1354.     
  1355. #ifdef FW_BUILD_WIN
  1356.     ::DrawIconEx(*device, plfmDstRect.left, plfmDstRect.top, hIcon,
  1357.         plfmDstRect.right - plfmDstRect.left,
  1358.         plfmDstRect.bottom - plfmDstRect.top,
  1359.         0, NULL, DI_NORMAL);
  1360. #endif
  1361. #ifdef FW_BUILD_MAC
  1362.     ::RGBForeColor(&FW_kRGBBlack);
  1363.     ::RGBBackColor(&FW_kRGBWhite);
  1364.     ::PlotIconSuite(&plfmDstRect, atNone, ttNone, hIcon);
  1365. #endif
  1366. }
  1367.  
  1368.  
  1369.  
  1370. #ifdef FW_BUILD_MAC
  1371.  
  1372. //========================================================================================
  1373. // Macintosh-specific implementation
  1374. //========================================================================================
  1375.  
  1376. //----------------------------------------------------------------------------------------
  1377. //    FW_CPrivRasterizer::MacSelectInkAndStyle
  1378. //----------------------------------------------------------------------------------------
  1379.  
  1380. FW_Boolean FW_CPrivRasterizer::MacSelectInkAndStyle(FW_CGraphicDevice* device,
  1381.                                         FW_EShapeCategories shapeCategory,
  1382.                                         FW_ERenderVerbs renderVerb,
  1383.                                         const FW_PInk& ink,
  1384.                                         const FW_PStyle& style)
  1385. {
  1386.     
  1387.     device->SelectInk(ink, shapeCategory, renderVerb);
  1388.     FW_Boolean styleIsDash = device->SelectStyle(style, ink->GetTransferMode());
  1389.     device->SetInGrafPort();
  1390.     return styleIsDash;
  1391. }
  1392.  
  1393. //----------------------------------------------------------------------------------------
  1394. //    FW_CPrivRasterizer::MacCalcTextPosition
  1395. //----------------------------------------------------------------------------------------
  1396.  
  1397. FW_SPlatformPoint FW_CPrivRasterizer::MacCalcTextPosition(FW_CGraphicDevice* device,
  1398.                                                      short byteCount, const char* text,
  1399.                                                      FW_TextAlignment textAlignment,
  1400.                                                      const FW_SPlatformPoint& position) const
  1401. {
  1402.     FW_ASSERT(device->GetPlatformCanvas() == FW_QDGlobals.thePort);
  1403.  
  1404.     FW_ASSERT(text != NULL);
  1405.  
  1406.     FW_SPlatformPoint plfmPos(position);
  1407.  
  1408.     if((textAlignment & FW_kTextAlignPrivUsePosMask) == FW_kTextAlignUseCurrentPos)
  1409.     {
  1410.         ::GetPen(&plfmPos);
  1411.     }
  1412.     else
  1413.     {
  1414.         // ----- Adjust Horizontal position
  1415.         FW_TextAlignment hAlign = textAlignment & FW_kTextAlignPrivHorzAlignMask;
  1416.         if (hAlign != FW_kTextAlignLeft)
  1417.         {
  1418.             short textWidth = ::TextWidth(text, 0, byteCount);
  1419.             if (hAlign == FW_kTextAlignRight)
  1420.                 plfmPos.h -= textWidth;
  1421.             else
  1422.                 plfmPos.h -= (textWidth / 2);
  1423.         }
  1424.     }
  1425.     
  1426.     // ----- In both cases we need to adjust the vertical position
  1427.     FW_TextAlignment vAlign = textAlignment & FW_kTextAlignPrivVertAlignMask;
  1428.     if (vAlign != FW_kTextAlignBaseLine)
  1429.     {
  1430.         FontInfo fi;
  1431.         ::GetFontInfo(&fi);
  1432.         switch (vAlign)
  1433.         {
  1434.             case FW_kTextAlignTop:
  1435.                 plfmPos.v += fi.ascent;
  1436.                 break;
  1437.                 
  1438.             case FW_kTextAlignBottom:
  1439.                 plfmPos.v -= fi.descent;
  1440.                 break;
  1441.                 
  1442.             case FW_kTextAlignVCenter:
  1443.                 plfmPos.v += fi.ascent - ((fi.descent + fi.ascent) / 2);
  1444.                 break;
  1445.         }
  1446.     }
  1447.  
  1448.     return plfmPos;
  1449. }
  1450.  
  1451. //----------------------------------------------------------------------------------------
  1452. //    FW_CPrivRasterizer::MacStrikeOut
  1453. //----------------------------------------------------------------------------------------
  1454.  
  1455. void FW_CPrivRasterizer::MacStrikeOut(FW_CGraphicDevice* device,
  1456.                                 short beforePosX, short beforePosY)
  1457. {
  1458.     // ----- Get the pen position before drawing -----
  1459.     FW_SPlatformPoint afterPoint;
  1460.     ::GetPen(&afterPoint);
  1461.  
  1462.     FontInfo fi;
  1463.     ::GetFontInfo(&fi);
  1464.     short ySize = (fi.ascent + fi.descent) / 2;
  1465.  
  1466.     device->SetPenSize(1,1);
  1467.     device->SetInGrafPort();
  1468.     
  1469.     ::MoveTo(beforePosX, beforePosY - ySize);
  1470.     ::LineTo(afterPoint.h - 1, afterPoint.v - ySize);
  1471.     
  1472.     // ----- Restore the pen position -----
  1473.     ::MoveTo(afterPoint.h, afterPoint.v);
  1474. }
  1475.  
  1476. #endif
  1477.  
  1478. #ifdef FW_BUILD_WIN
  1479.  
  1480. //========================================================================================
  1481. // Windows-specific implementation
  1482. //========================================================================================
  1483.  
  1484. //----------------------------------------------------------------------------------------
  1485. //    FW_CPrivRasterizer::WinConvertRasterOp
  1486. //----------------------------------------------------------------------------------------
  1487.  
  1488. DWORD FW_CPrivRasterizer::WinConvertRasterOp(FW_TransferModes transferMode)
  1489. {
  1490.     if ((transferMode & 0xFFFF0000L) == 0)
  1491.         return (DWORD)transferMode;        // Native Raster ops
  1492.     else
  1493.     {
  1494.         FW_ASSERT(transferMode <= FW_LastTransferMode);
  1495.         return FW_gWinRasterOps[transferMode & 0x0000FFFFL];
  1496.     }
  1497. }
  1498.  
  1499. #endif
  1500.